/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.xelnaga.defiler.web.page.mapping;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UrlPathHelper;
import org.xelnaga.defiler.domain.FolderModel;
import org.xelnaga.defiler.domain.HtmlPageModel;
import org.xelnaga.defiler.domain.PageAliasModel;
import org.xelnaga.defiler.domain.SiteModel;
import org.xelnaga.defiler.service.FolderService;
import org.xelnaga.defiler.service.HtmlPageService;
import org.xelnaga.defiler.service.PageAliasService;
import org.xelnaga.defiler.service.SiteService;
import org.xelnaga.defiler.util.FormatUtils;

/**
 * @author Carsten Woelk [cwoelk at neteye dot de]
 * @author Felix Gnass [fgnass at neteye dot de]
 * @since 7.0
 */
@Component
public final class PageResolver {
	
	public final String SITE_ATTRIBUTE = PageResolver.class.getName() + ".site";

	public final String PAGE_ATTRIBUTE = PageResolver.class.getName() + ".page";

	private final Object NOT_FOUND = new Object();
	@Autowired
	private SiteService siteSerivce;
	@Autowired
	private FolderService folderService;
	@Autowired
	private HtmlPageService htmlPageService;
	@Autowired
	private PageAliasService pageAliasService;
	/**
	 * Returns the first Site that matches the given request. The PathCompleter
	 * is used to strip the servlet mapping from the request URI.
	 * @return The first matching Site, or <code>null</code> if no match is found
	 */
	public SiteModel getSite(HttpServletRequest request) {
		Object site = request.getAttribute(SITE_ATTRIBUTE);
		if (site == null) {
			site = resolveSite(request);
			exposeSite((SiteModel) site, request);
		}
		if (site == null || site == NOT_FOUND) {
			return null;
		}
//		Site result = (Site) site;
//		result.refreshIfDetached();
		return (SiteModel)site; 
	}

	protected void exposeSite(SiteModel site, HttpServletRequest request) {
		expose(site, request, SITE_ATTRIBUTE);
	}
	
	/**
	 * Returns the Page for the given request.
	 */
	public HtmlPageModel getPage(HttpServletRequest request) {
		Object page = request.getAttribute(PAGE_ATTRIBUTE);
		if (page == null) {
			page = resolvePage(request);
			exposePage((HtmlPageModel) page, request);
		}
		if (page == null || page == NOT_FOUND) {
			return null;
		}
		return (HtmlPageModel) page;
	}
		
	protected void exposePage(HtmlPageModel page, HttpServletRequest request) {
		expose(page, request, PAGE_ATTRIBUTE);
	}
	
	private SiteModel resolveSite(HttpServletRequest request) {
		String hostName = request.getServerName();
		return siteSerivce.getByHostName(hostName);
	}

	private HtmlPageModel resolvePage(HttpServletRequest request) {
        SiteModel site = getSite(request);
        if (site == null) {
            return null;
        }
        String lookupPath = getLookupPath(request);
        HtmlPageModel page = htmlPageService.getBySiteAndPath(site.getInode(), lookupPath);
        if (page == null) {
            page = resolveVirtualChildPage(site, lookupPath);
        }
        //Only need to handle default page. I.E no url path specified.
        if(page == null && StringUtils.isBlank(lookupPath)) {
        	page = site.getHtmlPage();
        }
        if (page == null || (null == page.getLive() || !page.getLive())) {
            return null;
        }
        return page;
    }
	
	private HtmlPageModel resolveVirtualChildPage(SiteModel site, String lookupPath) {
		//The path of page is not found, try to find by folder;
		FolderModel folder = folderService.getBySiteAndPath(site.getInode(), lookupPath);
		if(null != folder) {//This is the folder path
			if(StringUtils.isNotBlank(folder.getIndexPath())) {
				return htmlPageService.getBySiteAndPath(site.getInode(), folder.getIndexPath());
			} else {
				return htmlPageService.getByFolderAndMaxSortOrder(folder.getInode());
			}
		}
//		for (ContentPage parent : ContentPage.findByTypesAndSite(site.getSchema().getVirtualParents(), site)) {
//			String parentPath = parent.getPath();
//			if (lookupPath.startsWith(parentPath)) {
//				String tail = lookupPath.substring(parent.getPath().length());
//				if (tail.startsWith("/")) {
//					SystemPageType parentType = (SystemPageType) parent.getPageType();
//					return parentType.getVirtualChildType().resolve(parent, tail);
//				}
//			}
//		}
		return null;
	}

	public String getLookupPath(HttpServletRequest request) {
		String s = FormatUtils.stripExtension(FormatUtils.stripTrailingSlash(
				new UrlPathHelper().getPathWithinApplication(request)));
		return s.length() > 0 ? StringUtils.substringAfter(s, "/app") : "/";
	}
	
	private void expose(Object object, HttpServletRequest request, String attributeName) {
		if (object == null) {
			object = NOT_FOUND;
		}
		request.setAttribute(attributeName, object);
	}
	
	/**
	 * Resets all internally used attributes.
	 * @param request
	 */
	public void resetAttributes(HttpServletRequest request) {
		request.removeAttribute(SITE_ATTRIBUTE);
		request.removeAttribute(PAGE_ATTRIBUTE);
	}

	public PageAliasModel getPageAlias(SiteModel site, String path) {
		return pageAliasService.getBySiteAndPath(site.getInode(), path);
	}
}
